# Contributor: Oleg A. Khlybov <fougas@mail.ru>

# The supplementary `petsc-build` package contains the distilled PETSc build tree
# required at compile time by some packages (such as SLEPc).
# Regular users should use the `petsc` package.

# This package provides multiple library build flavors differentiated by
# the 3-character suffix XYZ as follows:
#
#  * X is the scalar type based on the Netlib's SDCZ notation:
#    - A for multiprecision or precision-neutral build
#    - S for single precision real
#    - D for double precision real
#    - C for single precision complex
#    - Z for double precision complex
#
#  * Y is the execution model:
#    - S for sequential code
#    - M for MPI parallel code
#    - T for multithreaded code, either bare threading or OpenMP, OpenACC etc.
#    - H for heterogeneous code with CUDA, OpenCL etc.
#
#  * Z is the build type:
#    - O for optimized build
#    - G for debugging build
#
# The suffix is used in the static and dynamic libraires as well as in PkgConfig .pc files.
# That is the ZMO suffix designates the optimized MPI parallel double precision complex library flavor.
# Consider the `pkg-config petsc-zmo --cflags` command to obtain the build-specific compilation flags.


_realname=petsc
pkgbase=mingw-w64-${_realname}
pkgname=("${MINGW_PACKAGE_PREFIX}-${_realname}" "${MINGW_PACKAGE_PREFIX}-${_realname}-build")
pkgver=3.17.3
pkgrel=1
arch=('any')
mingw_arch=('mingw32' 'mingw64' 'ucrt64' 'clang64' 'clang32')
pkgdesc='Sparse iterative (non)linear solver package (mingw-w64)'
depends=("${MINGW_PACKAGE_PREFIX}-gcc-libs"
         $([[ ${MINGW_PACKAGE_PREFIX} != *-clang-* ]] && \
           echo "${MINGW_PACKAGE_PREFIX}-gcc-libgfortran" || \
           echo "${MINGW_PACKAGE_PREFIX}-openmp")
         "${MINGW_PACKAGE_PREFIX}-hwloc"
         "${MINGW_PACKAGE_PREFIX}-metis"
         "${MINGW_PACKAGE_PREFIX}-msmpi"
         "${MINGW_PACKAGE_PREFIX}-openblas"
         "${MINGW_PACKAGE_PREFIX}-parmetis")
makedepends=('python'
             "${MINGW_PACKAGE_PREFIX}-cc"
             $([[ ${MINGW_PACKAGE_PREFIX} != *-clang-* ]] && echo "${MINGW_PACKAGE_PREFIX}-gcc-fortran"))
optdepends=("${MINGW_PACKAGE_PREFIX}-tcl: build & run test suite")
options=('strip' 'staticlibs')
license=('spdx:BSD-2-Clause')
url="https://www.mcs.anl.gov/petsc/"
source=("https://ftp.mcs.anl.gov/pub/petsc/release-snapshots/${_realname}-lite-${pkgver}.tar.gz"
        'all.tcl'
        'tclbuildtest.tcl'
        'petsc.test'
        'petsc-mat.test'
        '0001-mpi-detection-override.patch'
        '0002-openblas-clang.patch')
noextract=("${_realname}-lite-${pkgver}.tar.gz")
sha256sums=('5c24ade5e4b32cc04935ba0db1dafe48d633bebaaa30a3033f1e58788d37875f'
            'ec5072630e1c0309fe383669e9187790cd135a393c67bc4bc35cf60b0ba396ff'
            '15c7af25b91406d5fe5f26cfe00963b6cfde1c3dd466eb25f1b6fae299934966'
            '9662cc4104726c714f7961aba6f8c93bfb85f3d3f89b4908b0a55aedab41ca31'
            'fc95ca4ddc138d288f047835a68a84a11cb841c6cca146c6ef7d7e63e0836b1a'
            'bef5353d6d10de492c9832f24b41993c38d1b36a78eb55e7d49089ba72acc05a'
            '6f3b455b79b6d22ebf4189594bc9e17ccfbe4ffdd15843a9aa0698efa4a30cc2')

# Helper macros to help make tasks easier #
apply_patch_with_msg() {
  for _fname in "$@"
  do
    msg2 "Applying ${_fname}"
    patch -Nbp1 -i "${srcdir}"/${_fname}
  done
}

prepare() {
  [[ -d "${srcdir}"/build-${MSYSTEM} ]] && rm -rf "${srcdir}"/build-${MSYSTEM}
  mkdir -p "${srcdir}"/build-${MSYSTEM} && cd "${srcdir}"/build-${MSYSTEM}
  tar xzf $srcdir/${_realname}-lite-${pkgver}.tar.gz

  cd ${_realname}-${pkgver}
  apply_patch_with_msg \
    0001-mpi-detection-override.patch \
    0002-openblas-clang.patch
}

# Optimized build flavors
builds='dso dto dmo zso zto zmo sso sto smo cso cto cmo'

# Additional debugging build flavors, disabled by default due to huge library sizes
# builds="$builds dsg dtg dmg zsg ztg zmg ssg stg smg csg ctg cmg"

_petsc() {
  desc=
  opts="--with-single-library=1 --disable-shared --with-windows-graphics=0 --with-x=0 --with-hwloc=1 --with-openblas=1 --with-openblas-dir=$MINGW_PREFIX"
  pc="hwloc openblas"
  iflags=
  cflags="$CFLAGS"
  cxxflags="$CXXFLAGS"
  fflags="$CFLAGS -fallow-invalid-boz -fallow-argument-mismatch -I$MINGW_PREFIX/include"
  cppflags="$CPPFLAGS"
  ldflags="$LDFLAGS"
  pc_libs="$LIBS"
  libs="$LIBS"
  ld="$CXX"
  if [[ ${MINGW_PACKAGE_PREFIX} != *-clang-* ]]; then
    libs+=" -lgfortran -lquadmath"
    pc_libs="$libs"
  else
    opts+=" --with-fc=0"
  fi
  case $1 in
    ?m?)
      opts+=" --with-mpi=1 --with-mpi-compilers=0 --with-pthread=0 --with-openmp=0 --with-metis=1 --with-parmetis=1"
      pc+=" parmetis msmpi"
      libs+=" -lmsmpi"
      # pc_libs is not augmented because MPI is provided by the PkgConfig
      desc="MPI parallel"
    ;;
    ?t?)
      opts+=" --with-mpi=0 --with-pthread=0 --with-openmp=1"
      iflags="$iflags -I\${includedir}/mpiuni"
      ldflags+=" -fopenmp"
      desc="OpenMP multithreaded"
    ;;
    ?s?)
      opts+=" --with-mpi=0 --with-pthread=0 --with-openmp=0"
      iflags+=" -I\${includedir}/mpiuni"
      desc="Sequential"
    ;;
  esac
  case $1 in
    z*|d*)
      opts+=" --with-precision=double"
      desc+=" double precision"
    ;;
    c*|s*)
      opts+=" --with-precision=single"
      desc+=" single precision"
    ;;
  esac
  case $1 in
    d*|s*)
      opts+=" --with-scalar-type=real"
    ;;
    z*|c*)
      opts+=" --with-scalar-type=complex"
      desc+=" complex"
    ;;
  esac
  case $1 in
    *o)
      opts+=" --with-debugging=0"
    ;;
    *g)
      opts+=" --with-debugging=1"
      debug="-g -Og"
      cflags+=" $debug"
      cxxflags+=" $debug"
      fflags+=" $debug"
    ;;
  esac
}

build() {
  cd  "${srcdir}/build-${MSYSTEM}/${_realname}-${pkgver}"
  for build in ${builds}; do
    _petsc ${build}
    export PETSC_DIR=`pwd`
    /usr/bin/python configure --PETSC_ARCH=${build} ${opts} CC="$CC" CXX="$CXX" FC="gfortran" CFLAGS="$cflags" FFLAGS="$fflags" CXXFLAGS="$cxxflags" CPPFLAGS="$cppflags" LDFLAGS="$ldflags" LIBS="$libs" MAKEFLAGS="$MAKEFLAGS"
    make PETSC_ARCH=${build} all
    (
      cd ${build}/lib
      case ${build} in
        *o) strip -S *.a ;;
      esac
      ${ld} -shared -Wl,--enable-auto-import -Wl,--export-all-symbols -o lib${_realname}-${build}.dll -Wl,--out-implib,lib${_realname}.dll.a -Wl,--whole-archive lib${_realname}.a -Wl,--no-whole-archive ${ldflags} ${libs} $(pkg-config ${pc} --libs)
    )
  done
}

eval "package_${MINGW_PACKAGE_PREFIX}-${_realname}() { _package; }"
eval "package_${MINGW_PACKAGE_PREFIX}-${_realname}-build() { _package_build; }"

_package() {
  cd ${srcdir}/build-${MSYSTEM}/${_realname}-${pkgver}
  mkdir -p ${pkgdir}${MINGW_PREFIX}/{bin,lib/pkgconfig,lib/${_realname},include/${_realname},share/test/${_realname}/{ksp,mat}}
  (
    cd include
    cp *.h ${pkgdir}${MINGW_PREFIX}/include/${_realname}
    cd ${_realname}
    cp -R finclude mpiuni ${pkgdir}${MINGW_PREFIX}/include/${_realname}
    cd ${pkgdir}${MINGW_PREFIX}/include/${_realname}
    find . \( ! -name '*.h' -a -type f \) -delete
  )
  (
    cd ${srcdir}
    cp {all,tclbuildtest}.tcl {petsc,petsc-mat}.test ${pkgdir}${MINGW_PREFIX}/share/test/${_realname}
  )
  (
    cd src/ksp/ksp/tutorials
    cp ex1.c ex2.c ex1f.F90 ex2f.F90 ${pkgdir}${MINGW_PREFIX}/share/test/${_realname}/ksp
  )
  (
    cd src/mat/tutorials
    cp ex15.c ex15f.F90 ${pkgdir}${MINGW_PREFIX}/share/test/${_realname}/mat
  )
  for build in ${builds}; do
    _petsc ${build}
    (
      cd ${build}/lib
      mkdir -p ${pkgdir}${MINGW_PREFIX}/lib/${_realname}/${build}
      cp *.a ${pkgdir}${MINGW_PREFIX}/lib/${_realname}/${build}
      cp *.dll ${pkgdir}${MINGW_PREFIX}/bin
    )
    (
      cd ${build}/include
      mkdir -p ${pkgdir}${MINGW_PREFIX}/include/${_realname}/${build}
      cp *.h ${pkgdir}${MINGW_PREFIX}/include/${_realname}/${build}
      if [[ ${MINGW_PACKAGE_PREFIX} != *-clang-* ]]; then
        cp *.mod ${pkgdir}${MINGW_PREFIX}/include/${_realname}/${build}
      fi
    )
    echo "
      prefix=${MINGW_PREFIX}
      libdir=\${prefix}/lib/${_realname}
      includedir=\${prefix}/include/${_realname}
      Name: ${_realname}
      URL: ${url}
      Version: ${pkgver}
      Description: ${desc} PETSc build
      Requires.private: ${pc}
      Cflags: -I\${includedir}/${build} -I\${includedir} ${iflags}
      Libs.private: -L\${libdir}/${build} -l${_realname} ${ldflags} ${pc_libs}
      Libs: -L\${libdir}/${build} -l${_realname}
    " | sed '/^\s*$/d;s/^\s*//' > ${pkgdir}${MINGW_PREFIX}/lib/pkgconfig/${_realname}-${build}.pc
  done
}

_package_build() {
  mkdir -p ${pkgdir}${MINGW_PREFIX}/src
  cd ${srcdir}/build-${MSYSTEM}
  cp -R ${_realname}-${pkgver} ${pkgdir}${MINGW_PREFIX}/src
  cd ${pkgdir}${MINGW_PREFIX}/src
  find . -regextype posix-extended \( -regex '.*\.(o|dll|log|DIR)$' -or -regex '.*/__pycache__' \) -exec rm -rf {} +
  for build in ${builds}; do
    find . -regextype posix-extended -regex ".*$build/(bin|obj|tests)" -exec rm -rf {} +
    si=${MINGW_PREFIX}/src/${_realname}-${pkgver}/include
    sb=${MINGW_PREFIX}/src/${_realname}-${pkgver}/${build}/include
    pi=${MINGW_PREFIX}/include/petsc
    pb=${MINGW_PREFIX}/include/petsc/${build}
    sed -r -i \
      -e "s%(PETSC_(C|F)C_INCLUDES)[[:space:]]+.*$%\\1 = -I${sb} -I${si}%" \
      -e "s%(PETSC_(C|F)C_INCLUDES_INSTALL)[[:space:]]+.*$%\\1 = -I${pb} -I${pi}%" \
      ${_realname}-${pkgver}/${build}/lib/petsc/conf/petscvariables
  done
  echo "
    petsc_pkgver=${pkgver}
    petsc_builds=\"${builds}\"
  " | sed '/^\s*$/d;s/^\s*//' > ${_realname}-${pkgver}/petsc
}
